#include "ContinuousSequencer.h"
//#include <QCleanlooksStyle>
#include <QPlastiqueStyle>

ContinuousSequencer::ContinuousSequencer( QMainWindow* parent,float y)
    : w(parent),
      scene(new MutaScene(parent)),
      cursor(new MutaCursor(1000,800)),
      view(new MutaGraphicsView(parent,scene,cursor)),
      layerButton(parent),
      layerTextEdit(parent),
      markerNum(0),
      y(y)
{
    scene->setItemIndexMethod(QGraphicsScene::NoIndex);
    view->setGeometry(
        parent->geometry().width() * 0.00f,
        0,
        parent->geometry().width() * 1.0f,
        parent->geometry().height() - 45
    );
    setY(y);
    view->show();
    setEditMode(Muta::Line);
    //scene->addItem(cursor);
    //cursor->setX(0);
    QPalette pal;
    QLinearGradient gradient(0, 0, 0, 255);
    gradient.setColorAt(0.0, QColor(200,200,220,255));
    gradient.setColorAt(0.1, QColor(80,80,80,255));
    //gradient.setColorAt(0.6, QColor(0,0,0));
    gradient.setColorAt(0.6, QColor(10,40,55));
    gradient.setColorAt(0.975, QColor(30,30,30,255));
    gradient.setColorAt(1.0, QColor(50,50,50,255));
    gradient.setInterpolationMode(QGradient::ColorInterpolation);
    pal.setBrush(QPalette::Button,gradient);
    pal.setColor(QPalette::ButtonText,QColor(200,200,200,255));
    layerButton.setGeometry(
        parent->geometry().width()*0.715,
        parent->geometry().height()*0.005,
        parent->geometry().width()*0.065,
        parent->geometry().height()*0.035
    );
    QStringList layers;
    layers << "Layer 1" << "Layer 2" << "Layer 3" << "Layer 4" << "Layer 5";
    layerButton.addItems(layers);
    layerButton.setStyle(new QPlastiqueStyle());
    layerButton.show();

    layerButton.setPalette(pal);
    connect(&layerButton,SIGNAL(currentIndexChanged(int)),view,SLOT(setLayer(int)));

    layerTextEdit.setGeometry(
        parent->geometry().width()*0.785,
        parent->geometry().height()*0.005,
        parent->geometry().width()*0.065,
        parent->geometry().height()*0.035
    );
    layerTextEdit.setFontPointSize(12);
    layerTextEdit.show();
    layerTextEdit.setStyle(new QPlastiqueStyle());

    layerTextEdit.setPalette(pal);
    connect(&layerTextEdit,SIGNAL(textChanged()),this,SLOT(textChanged()));

    connect(scene,SIGNAL(deletingItem(QString)),this,SLOT(removeCollidingItem(QString)));
    connect(view,SIGNAL(repeatObjectAdded(MutaRepeat*)),this,SLOT(addRepeatMarker(MutaRepeat*)));
}

ContinuousSequencer::~ContinuousSequencer()
{
    delete view;
    delete scene;
}

void ContinuousSequencer::textChanged()
{
    layerButton.setItemText(view->getLayer(),layerTextEdit.document()->toPlainText());
}

void ContinuousSequencer::mutaTimeEvent(qreal delta)
{
    QReadLocker readLocker(scene->getItemLock());
    QWriteLocker collLocker(&collidingLock);
    cursor->setTime(delta);
    if(cursor->x() > scene->sceneRect().width()) {
        cursor->setX(0);
        qDebug() << "reseting Cursor";
    }
    int type;
    for(int i=0;i<collidingItems.size();i++) {
        type = collidingItems.at(i)->type();
        switch(type) {
            case Muta::Event :
                if((collidingItems.at(i)->x() > cursor->x()) || ( (((MutaEvent*)collidingItems.at(i))->rect().width()+collidingItems.at(i)->x()) < cursor->x())) {
                    emit release(((MutaLine*)collidingItems.at(i))->getObjectID(),layerButton.itemText(((MutaEvent*)collidingItems.at(i))->getLayer()),(1-(collidingItems.at(i)->y()/view->height()))*12);
                    ((MutaEvent*)collidingItems.at(i))->playing = false;
                    collidingItems.remove(i);
                }
                break;
            case Muta::Curve :
            case Muta::Line :
                if((collidingItems.at(i)->x() > cursor->x()) || ( (((MutaLine*)collidingItems.at(i))->path().boundingRect().width()+collidingItems.at(i)->x()) < cursor->x()) ) {
                    emit release(((MutaLine*)collidingItems.at(i))->getObjectID(),layerButton.itemText(((MutaLine*)collidingItems.at(i))->getLayer()),(1-(collidingItems.at(i)->y()/view->height()))*12);
                    ((MutaLine*)collidingItems.at(i))->playing = false;
                    collidingItems.remove(i);
                }
                break;
        }
    }


    //Check to see if an event has begun
    float percent;
    float value;

    foreach(QGraphicsItem* cItem,scene->items()) {
        type = cItem->type();
        //qDebug() << type;
        switch(type) {
            case Muta::Event :
                if(
                        (cItem->x() <= cursor->x()) && ( (((MutaEvent*)cItem)->rect().width()+cItem->x()) >= cursor->x())
                 ) {
                    if( !((MutaEvent*)cItem)->playing  ) {
                        emit attack(((MutaEvent*)cItem)->getObjectID(),layerButton.itemText(((MutaEvent*)cItem)->getLayer()),(1-(cItem->y()/view->height())));
                        ((MutaEvent*)cItem)->playing = true;
                        collidingItems.append(cItem);
                    }
                }
                break;
            case Muta::Curve :
                if(
                    (cItem->x() <= cursor->x()) && ( (((MutaCurve*)cItem)->path().boundingRect().width()+cItem->x()) >= cursor->x())
                ) {
                    if( !((MutaCurve*)cItem)->playing  ) {
                        //qDebug() << layerButton.itemText(0);
                        //qDebug() << ((MutaLine*)cItem)->getLayer();
                        emit attack(((MutaLine*)cItem)->getObjectID(),layerButton.itemText(((MutaCurve*)cItem)->getLayer()),((cItem->y()/view->height())));
                        ((MutaCurve*)cItem)->playing = true;
                        collidingItems.append(cItem);
                    } else {
                        QPolygonF curvePoly = ((MutaCurve*)cItem)->getCurvePoly();
                        QPointF point1,point2;
                        float count=0;
                        /*
                        for(int i=0;i<curvePoly.size()-1;i++) {
                            if(cursor->x() >= ((curvePoly.at(i).x()) + cItem->x())) {
                                point2 = curvePoly.at(i+1);
                                point1 = curvePoly.at(i);
                                count++;
                                continue;
                            }
                        }
                        */
                        bool con=true;
                        while(con) {
                            if(cursor->x() <= ((curvePoly.at(count).x()) + cItem->x())) {
                                point2 = curvePoly.at(count);
                                point1 = curvePoly.at(count-1);
                                con = false;
                            }
                            count++;
                        }
                        double interp = ((cursor->x()) - (point1.x()+cItem->x())) / ((point2.x()+cItem->x())- (point1.x()+cItem->x()));
                        interp = interp;
                        double value = ((((point2.y() - point1.y())*interp) + point1.y()) + cItem->y())/scene->height();
                        //qDebug() << "interp" << interp << "cursor" << cursor->x() << "point 1" << (point1.x()+cItem->x()) << "point2" <<  (point2.x()+cItem->x());
                        //qDebug() << count;
                        //qDebug() << interp;
                        //qDebug() << value;
                        emit sustain(((MutaLine*)cItem)->getObjectID(),layerButton.itemText(((MutaLine*)cItem)->getLayer()),value);
                    }
                }
                break;
            case Muta::Line :
                if(
                    (cItem->x() <= cursor->x()) && ( (((MutaLine*)cItem)->path().boundingRect().width()+cItem->x()) >= cursor->x())
                ) {
                    if( !((MutaLine*)cItem)->playing  ) {
                        emit attack(((MutaLine*)cItem)->getObjectID(),layerButton.itemText(((MutaLine*)cItem)->getLayer()),1.0 -((cItem->y()/view->height())));
                        ((MutaLine*)cItem)->playing = true;
                        collidingItems.append(cItem);
                    } else {
                        //Fix percentages, needs to be different for each link?
                        percent = (cursor->x() - ((MutaLine*)cItem)->pos().x())/((MutaLine*)cItem)->boundingRect().width();
                        value =  ((MutaLine*)cItem)->mapToScene(((MutaLine*)cItem)->path().pointAtPercent(percent)).y();
                        value = 1.0 -((value/view->scene()->height()));
                        emit sustain(((MutaLine*)cItem)->getObjectID(),layerButton.itemText(((MutaLine*)cItem)->getLayer()),value);
                        //qDebug() << cursor;
                        //qDebug() << ((MutaLine*)cItem)->shape().intersected(cursor->getCursorPath()).toFillPolygon().boundingRect().x();
                        //view->scene()->addPath( ((MutaLine*)cItem)->shape().intersected(cursor->getCursorPath()));
                        //view->scene()->addPolygon(((MutaLine*)cItem)->shape().intersected(cursor->getCursorPath()).toFillPolygon());
                        //qDebug() << cursor->getCursorPath().intersected(((MutaLine*)cItem)->shape()).toFillPolygon().boundingRect().x();
                        //qDebug() << cursor->getCursorPath().intersects(((MutaLine*)cItem)->shape());

                        /*
                        //QGraphicsPolygonItem* intersect = new QGraphicsPolygonItem(((MutaLine*)cItem)->shape().intersected(cursor->getCursorPath()).toFillPolygon());
                        QGraphicsPolygonItem* intersect = new QGraphicsPolygonItem((cursor->getCursorPath().intersected(((MutaLine*)cItem)->shape())).toFillPolygon());
                        QPen pen;
                        pen.setColor(QColor(255,0,0,255));
                        intersect->setPen(pen);
                        qDebug() << intersect->x();
                        qDebug() << intersect->y();
                        intersect->setX(cursor->x());
                        view->scene()->addItem(intersect);
                        */
                    }
                }
                break;
            case Muta::Repeat :
                if(cItem->x() <= cursor->x()) {
                    if(markerNum!=0) {
                        if(cItem->x()==markers.at(markerNum)->x()) {
                            cursor->setPixels(markers.at(markerNum-1)->x());
                        } else  {

                        }
                    } else {
                        cursor->reset();
                    }
                }
                break;
        }
    }
    //scene->getItemLock()->unlock();
}

void ContinuousSequencer::setY(int y)
{
    view->setGeometry(view->geometry().x(),y,view->geometry().width(),view->geometry().height());
}

void ContinuousSequencer::setEditMode(Muta::MutaType editMode)
{
    this->editMode = editMode;
    view->setEditMode(editMode);
    emit editModeChanged(editMode);
}

MutaGraphicsView* ContinuousSequencer::getView()
{
    return view;
}

void ContinuousSequencer::lineEditing()
{
    setEditMode(Muta::Line);
}

void ContinuousSequencer::eventEditing()
{
    setEditMode(Muta::Event);
}
void ContinuousSequencer::repeatEditing()
{
    setEditMode(Muta::Repeat);
}

void ContinuousSequencer::curveEditing()
{
    setEditMode(Muta::Curve);
}

void ContinuousSequencer::tendrilEditing()
{
    setEditMode(Muta::AutoTendril);
}

void ContinuousSequencer::blendEditing()
{
    setEditMode(Muta::Blend);
}

void ContinuousSequencer::strangeAttractorEditing()
{
    setEditMode(Muta::StrangeAttractor);
}

MutaCursor* ContinuousSequencer::getCursor()
{
    return cursor;
}

MutaScene* ContinuousSequencer::getScene()
{
    return scene;
}

void ContinuousSequencer::removeCollidingItem(QString objectID)
{
    QWriteLocker collLocker(&collidingLock);
    for(int i=0;i<collidingItems.size();i++) {
        if(objectID.compare(((MutaLine*)collidingItems.at(i))->getObjectID())==0) {
            emit release(((MutaLine*)collidingItems.at(i))->getObjectID(),layerButton.itemText(((MutaEvent*)collidingItems.at(i))->getLayer()),(1-(collidingItems.at(i)->y()/view->height()))*12);
            ((MutaEvent*)collidingItems.at(i))->playing = false;
            qDebug() << "removing item: " << objectID;
            //delete collidingItems.at(i);
            collidingItems.remove(i);
            continue;
        }
    }
}

void ContinuousSequencer::stopAllNotes()
{
    for(int i=0;i<collidingItems.size();i++) {
        emit release(((MutaLine*)collidingItems.at(i))->getObjectID(),layerButton.itemText(((MutaEvent*)collidingItems.at(i))->getLayer()),(1-(collidingItems.at(i)->y()/view->height()))*12);
        ((MutaEvent*)collidingItems.at(i))->playing = false;
        //collidingItems.remove(i);
    }
    collidingItems.clear();
}

void ContinuousSequencer::startAllNotes()
{
    for(int i=0;i<collidingItems.size();i++) {
        emit attack(((MutaLine*)collidingItems.at(i))->getObjectID(),layerButton.itemText(((MutaCurve*)collidingItems.at(i))->getLayer()),((collidingItems.at(i)->y()/view->height())));
    }
}

static bool mutaLessThan(MutaRepeat* object1,MutaRepeat* object2)
{
    return object1->x() < object2->x();
}

void ContinuousSequencer::addRepeatMarker(MutaRepeat *repeat)
{
    markers.append(repeat);
    qSort(markers.begin(),markers.end(),mutaLessThan);
    for(int i=0;i<markers.size();i++) {
        qDebug() << markers.at(i)->getObjectID() << ((MutaRepeat*)markers.at(i))->x();
    }
    QObject::connect(repeat,SIGNAL(destroyed(QObject*)),this,SLOT(removeRepeatMarker(QObject*)));
}

void ContinuousSequencer::removeRepeatMarker(QObject *repeat)
{
    qDebug() << "Removing RepeatMarker";
    if(markerNum==markers.size()-1) {
        if(markerNum!=0) {
            markerNum -=1;
        }
    }
    markers.removeOne( ((MutaRepeat*)repeat));
    qSort(markers.begin(),markers.end(),mutaLessThan);
    for(int i=0;i<markers.size();i++) {
        qDebug() << markers.at(i)->getObjectID() << ((MutaRepeat*)markers.at(i))->x();
    }
}

void ContinuousSequencer::incrementMarker()
{
    //qDebug() << markers.size();
    //qDebug() << "math" << (markerNum+1) % (markers.size());
    if(markers.size() > 0) {
        markerNum = (markerNum+1) % (markers.size());
        if(markerNum!=0) {
            cursor->setPixels(markers.at(markerNum-1)->x());
        } else {
            cursor->reset();
        }
        qDebug() << "Changed active repeat to" << markerNum;
    }
}
void ContinuousSequencer::decrementMarker()
{
    //qDebug() << "size" << markers.size();
    //qDebug() <<  "markerNum" << markerNum -1;
    if(markerNum>0) {
        markerNum = (markerNum-1) % markers.size();
        if(markerNum== -1) {
            markerNum = markers.size()-1;
        }
        cursor->setPixels(markers.at(markerNum)->x());
    } else {
        cursor->reset();
    }
    qDebug() << "markerNum" << markerNum;
}

void ContinuousSequencer::windowResized()
{
    setY(w->geometry().height() * 0.05);
    view->setGeometry(
        w->geometry().width() * 0.000,
        w->geometry().height() * 0.05,
        w->geometry().width() * 1.0f,
        w->geometry().height() *0.95
    );

    //buttonSizeX = w->geometry().width()*0.0276;
    //buttonSizeY = w->geometry().height()*0.035;

    layerButton.setGeometry(
        w->geometry().width()*0.715,
        w->geometry().height()*0.006,
        w->geometry().width()*0.065,
        w->geometry().height()*0.035
    );
    layerTextEdit.setGeometry(
        w->geometry().width()*0.785,
        w->geometry().height()*0.006,
        w->geometry().width()*0.065,
        w->geometry().height()*0.035
    );
}

